/*
 * Copyright Hundsun Technologies Inc. All Rights Reserved.
 */

package contract

import (
	"github.com/golang/protobuf/proto"
	"hundsun.com/hsl/hschain/common/types"
	pbcom "hundsun.com/hsl/hschain/protos/common"
	"hundsun.com/hsl/hschain/store/db"
)

// CodeDB 合约代码存储对象
type CodeDB struct {
	get db.DatabaseGet
}

// NewContractCodeDB new ContractCodeStore
func NewContractCodeDB(get db.DatabaseGet) *CodeDB {
	return &CodeDB{get: get}
}

// GetContractCode get ContractCode from address
func (c *CodeDB) GetContractCode(address string) (*pbcom.Contract, error) {
	if c.get == nil {
		return nil, types.ErrNotFound
	}
	v, err := c.get.Get(GenContractCodeKey(address))
	if err != nil {
		return nil, err
	}
	code := &pbcom.Contract{}
	err = proto.Unmarshal(v, code)
	if err != nil {
		return nil, err
	}
	return code, nil
}

// GetContractCodes batch get ContractCode from address
func (c *CodeDB) GetContractCodes(names []string) ([]*pbcom.Contract, error) {
	if c.get == nil {
		return nil, types.ErrNotFound
	}
	keys := make([][]byte, len(names))
	for i, key := range names {
		keys[i] = GenContractVersionKey(key)
	}
	values, err := c.get.Gets(keys)
	if err != nil {
		return nil, err
	}
	var cts []*pbcom.Contract
	for _, v := range values {
		code := &pbcom.Contract{}
		err = proto.Unmarshal(v, code)
		if err != nil {
			continue
		}
		cts = append(cts, code)
	}
	return cts, nil
}

// CodeKV from Contract to kv
func CodeKV(ct *pbcom.Contract) (*pbcom.KeyValue, error) {
	kv := &pbcom.KeyValue{}
	kv.Key = GenContractCodeKey(ct.Address)
	v, err := proto.Marshal(ct)
	if err != nil {
		return nil, err
	}
	kv.Value = v
	return kv, nil
}

// GenContractCodeKey generate ContractCode key
func GenContractCodeKey(address string) []byte {
	return []byte(db.NamespaceContract + address)
}
